package pushmsg

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"gitee.com/sailinst/utils"
	"gitee.com/sailinst/utils/random"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type res struct {
	Ret  int
	Code string
	Msg  string
}
type many struct {
	U interface{} `json:"u"`
	M interface{} `json:"m"`
}

// var msg map[string]string

type PushClientMessage struct {
	Id int64

	NamePerson         string
	Birthday           string
	Name               string
	FromName           string
	FromUserName       string
	RoomName           string
	Logo               string
	MsgFromType        string
	MsgType            string
	MsgNotificationStr string
	Img                string
	Title              string
	NoticeTitle        string
	Summary            string
	Content            string
	Status             bool
	IsClick            bool //可点
	CreateDate         time.Time
	ResponseDate       time.Time
}
type AliPushMsg struct {
	ClientMsg PushClientMessage
}

func (a *AliPushMsg) SendDelayedmsg(target string) bool {
	log.Println("aaaaaaaaaaaaaaaaaaaaaaa", a)
	log.Println("target", target)
	if _, res := AliPushMessage("one", target, a); res != nil {
		if len(res.MessageId) > 1 {
			time.Sleep(100 * time.Millisecond)
			return true
		} else {
			return false
		}
	} else {
		log.Println("res is nil")

	}
	return false
}
func PushMessage(action string, users interface{}, m *PushClientMessage) (bool, *res) {
	//func PushMessage(action string, users interface{}, m string) (bool, *res) {
	values := make(url.Values)
	var resp *http.Response
	var mSg []byte
	var user []byte
	var err error
	if action == "many" {
		data := new(many)
		data.U = users
		data.M = m
		if mSg, err = json.Marshal(data); err != nil {
			return false, nil
		}
	} else {
		mSg, err = json.Marshal(m)
		user, _ = json.Marshal(users)
		if err != nil {
			return false, nil
		}
	}
	switch action {
	case "one":
		values.Add("uid", string(user))
		//url := "http://113.209.64.174:7172/1/push?"
		url := "http://10.11.22.123:7172/1/push?"
		url += values.Encode()
		resp, _ = http.Post(url, "text/plain", bytes.NewBuffer(mSg))
		if ok, respInfo := resp_to_unmarshal(resp); ok {
			return true, respInfo
		} else {
			return false, respInfo
		}
	case "many":
		//url := "http://113.209.64.174:7172/1/pushs"
		url := "http://10.11.22.123:7172/1/pushs"
		url += values.Encode()
		resp, _ = http.Post(url, "text/plain", bytes.NewBuffer(mSg))
		if ok, respInfo := resp_to_unmarshal(resp); ok {
			return true, respInfo
		} else {

			return false, respInfo
		}
	case "room":
		url := "http://113.209.64.174:7172/1/push/room?rid=0"
		//url := "http://60.205.171.80:7172/1/push/room?rid=0"
		resp, _ = http.Post(url, "text/plain", bytes.NewBuffer(mSg))
		if ok, respInfo := resp_to_unmarshal(resp); ok {
			return true, respInfo
		} else {
			return false, respInfo
		}
	case "all":
		//url := "http://113.209.64.174:7172/1/push/all"
		url := "http://113.209.64.174:7172/1/push/all"
		resp, _ = http.Post(url, "text/plain", bytes.NewBuffer(mSg))
		if ok, respInfo := resp_to_unmarshal(resp); ok {
			return true, respInfo
		} else {
			return false, respInfo
		}
	default:
		return false, nil
	}
}

func resp_to_unmarshal(resp *http.Response) (bool, *res) {
	re := new(res)
	defer resp.Body.Close()
	if ss, err := ioutil.ReadAll(resp.Body); err != nil {
		log.Println("读取查询结果页面时发生错误，err is", err)
		re.Code = "2001"
		re.Msg = err.Error()
		return false, re
	} else {
		if err := json.Unmarshal(ss, re); err != nil {
			log.Println("获取查询结果时发生错误 ,err is:", err, " res is:", string(ss))
			re.Code = "2002"
			re.Msg = err.Error()
			return false, re
		} else {
			re.Code = "1000"
			re.Msg = "OK"
			return true, re
		}
	}
}

type AliRespInfo struct {
	Code      string
	Message   string
	RequestId string
	MessageId string
	HostId    string
}

var (
	AliCloudAppKey      = "23665956" // 23636409
	AliCloudAccessKeyId = "WC9nreih4P8Mbwwz"
	AlicloudAppSecret   = "HVllgK8DF9pvURVnTm0dtbFIqS8e6l"
)

//  xml 解析
func Ali_resp_to_unmarshal(resp *http.Response) (bool, *AliRespInfo) {
	re := new(AliRespInfo)
	if resp.Body == nil {
		return false, re
	}
	if ss, err := ioutil.ReadAll(resp.Body); err != nil {
		log.Println("读取查询结果页面时发生错误，err is", err)
		resp.Body.Close()
		return false, re
	} else {
		if err := xml.Unmarshal(ss, re); err != nil {
			log.Println("获取查询结果时发生错误 ,err is:", err, " res is:", string(ss))
			resp.Body.Close()
			return false, re
		} else {
			resp.Body.Close()
			return true, re
		}
	}
}
func AliPushNotice(action string, users interface{}, client_msg *AliPushMsg) (bool, *AliRespInfo) {
	url_val := "https://cloudpush.aliyuncs.com/?"
	push_msg_par := new(PushMsgParameter)
	push_msg_par.AccessKeyId = AliCloudAccessKeyId
	push_msg_par.Action = "Push"    // PushNoticeToiOS  //PushMessageToAndroid //
	push_msg_par.IOSApnsEnv = "DEV" // PRODUCT   生产环境

	push_msg_par.RegionId = "cn-hangzhou"
	push_msg_par.SignatureNonce = random.RandomAlphanumeric(16)
	push_msg_par.SignatureVersion = "1.0"
	push_msg_par.SignatureMethod = "HMAC-SHA1"
	push_msg_par.Version = "2016-08-01"
	push_msg_par.Timestamp = time.Now().UTC().Format("2006-01-02T15:04:05Z")
	push_msg_par.AppKey = AliCloudAppKey
	msg_byte, _ := json.Marshal(client_msg)
	push_msg_par.iOSExtParameters = string(msg_byte)
	push_msg_par.iOSBadge = 1
	//push_msg_par.AndroidOpenType = "com.rongshudata.zhenwo.activity.SecondActivity"
	push_msg_par.AndroidActivity = "com.rongshudata.zhenwo.activity.SecondActivity"
	push_msg_par.AndroidXiaoMiActivity = "com.rongshudata.zhenwo.activity.SecondActivity"
	push_msg_par.AndroidXiaoMiNotifyTitle = "真我App消息通知"
	push_msg_par.AndroidXiaoMiNotifyBody = client_msg.ClientMsg.Content
	// push_msg_par.AndroidExtParameters = string(msg_byte)
	push_msg_par.AndroidNotificationBarType = 2
	push_msg_par.StoreOffline = "true"
	switch action {
	case "one": // 单发消息
		str := users.(string)

		push_msg_par.Target = "ACCOUNT"
		push_msg_par.TargetValue = str

	case "many":
		str := strings.Join(users.([]string), ",")
		log.Println(str)
		return false, nil
	case "room":
		push_msg_par.Target = "TAG"
		push_msg_par.KeyType = "ACCOUNT"
		push_msg_par.TargetValue = users.(string)
	case "rooms":
		push_msg_par.Target = "TAG"
		push_msg_par.KeyType = "ACCOUNT"
		push_msg_par.TargetValue = strings.Join(users.([]string), ",")
	case "all": // 发广播消息
		push_msg_par.Target = "ALL"
		push_msg_par.TargetValue = "all"
	default:
		return false, nil
	}
	push_msg_par.DeviceType = "ALL"
	push_msg_par.PushType = "NOTICE" // 消息提示
	push_msg_par.Title = "真我"

	push_msg_par.Body = util.Sub_suffix(client_msg.ClientMsg.Content, 38)

	signture, val := GetAliSignature(push_msg_par)
	val.Add("Signature", signture)
	url_val += val.Encode()
	if resp, err := http.Post(url_val, "text/plain", nil); err == nil && resp != nil {
		if ok, respInfo := Ali_resp_to_unmarshal(resp); ok {
			return true, respInfo
		} else {
			return false, respInfo
		}
	} else {
		return false, nil
	}

}
func AliPushMessage(action string, users interface{}, client_msg *AliPushMsg) (bool, *AliRespInfo) {
	url_val := "https://cloudpush.aliyuncs.com/?"
	push_msg_par := new(PushMsgParameter)
	push_msg_par.AccessKeyId = AliCloudAccessKeyId
	push_msg_par.AppKey = AliCloudAppKey
	push_msg_par.Action = "Push"    // PushNoticeToiOS  //PushMessageToAndroid //
	push_msg_par.IOSApnsEnv = "DEV" // PRODUCT   生产环境

	push_msg_par.RegionId = "cn-hangzhou"
	push_msg_par.SignatureNonce = random.RandomAlphanumeric(16)
	push_msg_par.SignatureVersion = "1.0"
	push_msg_par.SignatureMethod = "HMAC-SHA1"
	push_msg_par.Version = "2016-08-01"
	push_msg_par.Timestamp = time.Now().UTC().Format("2006-01-02T15:04:05Z")

	// msg_byte, _ := json.Marshal(client_msg)
	// push_msg_par.iOSExtParameters = string(msg_byte)
	push_msg_par.iOSBadge = 1
	//push_msg_par.AndroidExtParameters = string(msg_byte)
	push_msg_par.AndroidNotificationBarType = 2
	push_msg_par.StoreOffline = "true"

	switch action {
	case "one": // 单发消息
		str := users.(string)
		push_msg_par.Target = "ACCOUNT"
		push_msg_par.TargetValue = str

	case "many":
		str := strings.Join(users.([]string), ",")
		log.Println(str)
		log.Println("ok")
		return false, nil
	case "room":
		push_msg_par.Target = "TAG"
		push_msg_par.KeyType = "ACCOUNT"
		push_msg_par.TargetValue = users.(string)
	case "rooms":
		push_msg_par.Target = "TAG"
		push_msg_par.KeyType = "ACCOUNT"
		push_msg_par.TargetValue = strings.Join(users.([]string), ",")
	case "all": // 发广播消息
		push_msg_par.Target = "ALL"
		push_msg_par.TargetValue = "all"
	default:
		return false, nil
	}
	push_msg_par.DeviceType = "ALL"
	push_msg_par.PushType = "MESSAGE" // MESSAGE
	push_msg_par.Title = "真我"
	msgbyte, _ := json.Marshal(client_msg)
	push_msg_par.Body = strings.Replace(string(msgbyte), ` `, `^&`, -1)
	signture, val := GetAliSignature(push_msg_par)
	val.Add("Signature", signture)
	url_val += val.Encode()
	//var resp *http.Response
	req, err := http.NewRequest("POST", url_val, nil)
	if err != nil {
		return false, nil
	}
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	if resp, err := client.Do(req); err != nil {
		log.Println("发送查询请求时发生错误 ，err is：", err)
		return false, nil
	} else {
		if ok, respInfo := Ali_resp_to_unmarshal(resp); ok {
			return true, respInfo
		} else {
			return false, respInfo
		}
	}
}

// push message 请求参数
type PushMsgParameter struct {
	AccessKeyId string
	Action      string
	RegionId    string
	//Devices          string
	Signature        string
	SignatureNonce   string
	SignatureVersion string
	SignatureMethod  string // = HMAC-SHA1
	Version          string
	Timestamp        string
	AppKey           string
	Target           string // 推送目标类别 ：DEVICE:根据设备推送 ACCOUNT:根据账号推送 ALIAS:根据别名推送  TAG:根据标签推送 ALL:推送给全部设备
	TargetValue      string //
	//tag
	TagName   string
	ClientKey string // 接受者
	KeyType   string // Tag推送的 推送类型

	DeviceType                 string // 设备类别 ： all
	PushType                   string // 消息类别： 1:msg 2: notice
	Title                      string // 消息头
	Body                       string // 消息内容
	ApnsEnv                    string
	IOSApnsEnv                 string // IOS APNs 环境  DEV表示开发环境，PRODUCT表示生产环境
	ExtParameters              string // 自定义消息结构  json串
	iOSExtParameters           string // 消息 ios
	iOSBadge                   int    // ios 消息提示数
	AndroidExtParameters       string // 消息 andriod
	AndroidNotificationBarType int    // andriod 通知栏样式
	StoreOffline               string // 用户不在线，72小时内会重新发送消息
	//AndroidOpenType            string // Activity  有效
	AndroidActivity          string
	AndroidXiaoMiActivity    string
	AndroidXiaoMiNotifyTitle string
	AndroidXiaoMiNotifyBody  string
}

func GetAliSignature(par *PushMsgParameter) (string, url.Values) {
	values := make(url.Values)
	values.Add("AccessKeyId", par.AccessKeyId)
	values.Add("Action", par.Action)
	values.Add("AppKey", par.AppKey)
	values.Add("RegionId", par.RegionId)
	//values.Add("Signature", par.Signature)
	values.Add("SignatureNonce", par.SignatureNonce)
	values.Add("SignatureVersion", par.SignatureVersion)
	values.Add("SignatureMethod", par.SignatureMethod)
	values.Add("Version", par.Version)
	values.Add("Timestamp", par.Timestamp)

	// tag
	values.Add("TagName", par.TagName)
	values.Add("ClientKey", par.ClientKey)
	values.Add("KeyType", par.KeyType)

	values.Add("Target", par.Target)
	values.Add("TargetValue", par.TargetValue)
	values.Add("DeviceType", par.DeviceType)
	values.Add("PushType", par.PushType)
	values.Add("Title", par.Title)
	values.Add("Body", par.Body)
	values.Add("iOSApnsEnv", par.IOSApnsEnv)
	values.Add("iOSExtParameters", par.iOSExtParameters)

	values.Add("iOSBadge", strconv.Itoa(par.iOSBadge))
	values.Add("AndroidExtParameters", par.AndroidExtParameters)
	// values.Add("AndroidOpenType", par.AndroidOpenType)
	values.Add("AndroidActivity", par.AndroidActivity)
	values.Add("AndroidXiaoMiActivity", par.AndroidXiaoMiActivity)
	values.Add("AndroidXiaoMiNotifyTitle", par.AndroidXiaoMiNotifyTitle)
	values.Add("AndroidXiaoMiNotifyBody", par.AndroidXiaoMiNotifyBody)

	values.Add("AndroidNotificationBarType", strconv.Itoa(par.AndroidNotificationBarType))

	values.Add("StoreOffline", par.StoreOffline)
	// 对values  按键名称 排序
	url_str := url.QueryEscape(values.Encode())
	source_str := "POST" + "&" + "%2F" + "&" + url_str
	sign, _ := Signature(AlicloudAppSecret+"&", source_str)
	return sign, values
}

func Signature(key, resource string) (signature string, err error) {
	sha1Hash := hmac.New(sha1.New, []byte(key))
	if _, err = sha1Hash.Write([]byte(resource)); err != nil {
		log.Println(err)
		return
	}
	resp := sha1Hash.Sum(nil)
	signature = base64.StdEncoding.EncodeToString(resp)
	return
}
